package com.xunk.equipment.service.mandun.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.xunk.common.core.domain.MandunFacility;
import com.xunk.common.core.exception.CustomException;
import com.xunk.common.core.text.Convert;
import com.xunk.common.core.utils.HttpUtil;
import com.xunk.common.core.utils.StringUtils;
import com.xunk.common.core.utils.serialization.JsonSerializer;
import com.xunk.common.core.web.domain.AjaxResult;
import com.xunk.common.redis.lock.IDistributeLock;
import com.xunk.common.redis.lock.RedisLock;
import com.xunk.common.redis.service.RedisService;
import com.xunk.equipment.config.MandunConfig;
import com.xunk.equipment.influxdb.InfluxCustomMapper;
import com.xunk.equipment.mapper.EquipmentMapper;
import com.xunk.equipment.service.mandun.constant.MandunConstant;
import com.xunk.equipment.service.mandun.enums.MandunIntervalEnum;
import com.xunk.equipment.service.mandun.service.IMandunService;
import com.xunk.equipment.service.mandun.util.MandunUtil;
import com.xunk.equipment.service.mandun.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * @ProjectName: xunk
 * @Package: com.xunk.equipment.service.ruying.mandun.service.impl
 * @ClassName: MandunServiceImpl
 * @Author: luanzhiwei
 * @Description: 曼顿service实现类
 * @Date: 2021/3/27 14:49
 * @Version: 1.0
 */
@Service
@Slf4j
@RefreshScope
public class MandunServiceImpl implements IMandunService {

    @Autowired
    private MandunConfig config;
    @Autowired
    private RedisService redisService;
    @Autowired
    private InfluxCustomMapper influxCustomMapper;
    @Autowired
    private EquipmentMapper equipmentMapper;
    //不能删RedisLock
    @Autowired
    private RedisLock redisLock;

    @Value("#{'${equipment.fake:0}'.split(',')}")
    private List<String> FAKE_SWITCH_SET;


    public static final String MM = "MM";
    public static final String DD = "dd";
    public static final String HH = "HH";

    private final IDistributeLock distributeLock;
    private static String redisLockValue;

    static {
        //保证每台服务都不相同，但是固定
        redisLockValue = RandomUtil.randomString(30);
    }

    public MandunServiceImpl(RedisLock redisLock) {
        this.distributeLock = redisLock.getLock(redisLockValue);
    }

    @Override
    public String getToken() {
        log.info("mandun->getToken开始");
        final JSONObject token = MandunUtil.getToken(config);
        JSONObject data = token.getJSONObject(MandunConstant.DATA);
        return data.getString(MandunConstant.ACCESS_TOKEN);
//        //从缓存中查询token
//        String accessToken = redisService.getCacheObject(MandunConstant.MANDUN_ACCESS_TOKEN);
//        if (StringUtils.isNotEmpty(accessToken)) {
//            log.info("mandun->accessToken不为空，直接返回");
//            return accessToken;
//        }
//        log.info("mandun->accessToken为空，查询refreshToken");
////        token为空，从缓存查询刷新token
//        String refreshToken = redisService.getCacheObject(MandunConstant.MANDUN_REFRESH_TOKEN_KEY);
//        if (StringUtils.isNotEmpty(refreshToken)) {
//            log.info("mandun->refreshToken不为空，刷新token");
//            return this.refreshToken(config, refreshToken);
//        }
//        //不存在refreshToken，调用曼顿接口获取token
//        return this.accessToken(config, StringUtils.EMPTY);
    }

    /**
     * 把refreshToken和accessToken存入redis
     *
     * @param refreshToken
     * @param accessToken
     */
    private void setToken2Redis(String refreshToken, String accessToken) {
        redisService.setCacheObject(MandunConstant.MANDUN_REFRESH_TOKEN_KEY, refreshToken, 60 * 60, TimeUnit.SECONDS);
        redisService.setCacheObject(MandunConstant.MANDUN_ACCESS_TOKEN, accessToken, 50 * 60, TimeUnit.SECONDS);
    }

    @Override
    public List<MandunFacility> getBoxes() {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOXES, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        JSONArray jsonArray = jsonObject.getJSONArray(MandunConstant.DATA);
        List<MandunFacility> facilities = JsonSerializer.deserializeArray(JsonSerializer.serialize(jsonArray), MandunFacility.class);
        return facilities;
    }

    @Override
    public AjaxResult getBox(String mac) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX, config.getAppKey(), getToken());
        request.put(MandunConstant.MAC, mac);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(jsonObject.getString(MandunConstant.MESSAGE));
        }
        return AjaxResult.success(jsonObject.getJSONObject(MandunConstant.DATA));
    }

    @Override
    public MandunFacilityProperty getBoxProperties(String mac) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX_PROPERTIES, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);
        request.put(MandunConstant.NODE_TYPE, MandunConstant.COMM);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        MandunFacilityProperty facilityProperty = JsonSerializer.deserialize(JsonSerializer.serialize(jsonObject), MandunFacilityProperty.class);
        return facilityProperty;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult getBoxChannelsRealtime(String deviceSn) {
        //先从redis中查询，如果存在直接返回
        //TODO 暂时去掉
//        String key = MandunConstant.MANDUN_REAL_TIME_KEY + deviceSn;
//        List<Object> cacheList = redisService.getCacheList(key);
//        if (CollectionUtils.isNotEmpty(cacheList)) {
//            return AjaxResult.success(cacheList);
//        }
        //不存在，查询曼顿接口
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX_CHANNELS_REALTIME, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, deviceSn);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        List<MandunRealTimeStatus> list =
                JsonSerializer.deserializeArray(JsonSerializer.serialize(jsonObject.getJSONArray(MandunConstant.DATA)), MandunRealTimeStatus.class);
        //当月用电量	electricity
        Map intervalRequest = new HashMap();
        intervalRequest.put(MandunConstant.TYPE, MandunConstant.MONTH);
        intervalRequest.put(MandunConstant.DEVICE_SN, deviceSn);
        intervalRequest.put(MandunConstant.YEAR, Convert.toStr(LocalDate.now().getYear()));
        intervalRequest.put(MandunConstant.MONTH, Convert.toStr(LocalDate.now().getMonthValue()));
        AjaxResult consumption = this.getIntervalElectricityConsumption(intervalRequest);
        if (!consumption.isSuccess() || !consumption.hasData()) {
            log.error("调用区间电量接口返回错误或data中无数据");
            return consumption;
        }
        List<MandunIntervalElectricityConsumption> data = JsonSerializer.deserializeArray(JsonSerializer.serialize(consumption.getData()), MandunIntervalElectricityConsumption.class);
        BigDecimal electricity = data.stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal.ZERO, BigDecimal::add);
        //当前功率	currentPower
        BigDecimal reduce = list.stream().map(MandunRealTimeStatus::currentPower).reduce(BigDecimal.ZERO, BigDecimal::add);
        //空开状态	list
        List<Map<String, Object>> statusList = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        list.forEach(item -> {
            if (item.getMainLine().equals("1")) {
                equipmentMapper.updateEquipmentOnline(deviceSn, convertOnline(item.ifOnline()));
                result.put("oc", item.isOc());
                result.put("addr", item.getAddr());
            }
            Map<String, Object> unit = new HashMap<>();
            unit.put("online", item.ifOnline());
            unit.put("addr", item.getAddr());
            unit.put("title", item.getTitle());
            unit.put("oc", item.isOc());
            unit.put("mainLine", item.getMainLine());
            statusList.add(unit);
        });
        result.put("electricity", electricity);
        result.put("currentPower", reduce.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP));
        result.put("list", statusList);
        //存入redis
        //TODO 暂时去掉
//        redisService.setCacheList(key, list);
//        redisService.expire(key, 1L, TimeUnit.DAYS);
        return AjaxResult.success(result);
    }

    @Override
    public MandunBoxAlarmResponse getBoxAlarm(String mac) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX_ALARM, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);//电箱编号
        request.put(MandunConstant.START, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
        request.put(MandunConstant.END, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
//        request.put(MandunConstant.PAGE_SIZE,);//int	默认：100	否	页记录大小
//        request.put(MandunConstant.PAGE,);//默认：1	否	页码
//        request.put(MandunConstant.TYPE,"W");//W表示告警/I表示信息，默认是W
//        request.put(MandunConstant.INCLUDE_CALM,"W");//false只包含告警产生；true包含告警产生、告警消除
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        MandunBoxAlarmResponse boxAlarmVO = JsonSerializer.deserialize(jsonObject.toJSONString(), MandunBoxAlarmResponse.class);
        return boxAlarmVO;
    }

    /**
     * 获取设备小时、日、月、年区间统计(电量、电流、电压、温度、漏电)
     * <p>
     * mac   必传
     * year  必传
     * month 月份,不传将返回当年每月数据
     * day   日,不传将返回当月每天数据
     * hour  小时（24时制）, 不传具体小时将返回当天每小时数据
     *
     * @param request
     * @return
     */
    @Override
    public AjaxResult getInterval(IntervalRequest request) {
        log.info("set {}  sn {}", JSON.toJSONString(FAKE_SWITCH_SET), request.getDeviceSn());
        if (FAKE_SWITCH_SET.contains(request.getDeviceSn())) {
            return getIntervalFake(request);
        } else {
            return getIntervalActual(request);
        }
    }

    private AjaxResult getIntervalActual(IntervalRequest request) {
        IntervalRequest.IntervalType type = IntervalRequest.IntervalType.getIntervalType(request.getType());
        List<IntervalResponse> result;
        final String deviceSn = request.getDeviceSn();
        switch (type) {
            case DAY:
                //近一天2小时一节点
                result = getDay(deviceSn);
                break;
            case MONTH:
                //近一月1天一节点
                result = getMonth(deviceSn);
                break;
            case SEASON:
                //近三月一星期一节点
                result = getQuarterYearResult(deviceSn);
                break;
            case HALF_YEAR:
                //近六月一月一节点
                result = getYear(deviceSn, true);
                break;
            case YEAR:
                //近一年一月一节点
                result = getYear(deviceSn, false);
                break;
            default:
                throw new CustomException("错误的查询类型");
        }

        //累计一年一节点（最多10年）--不存在此类场景

        return AjaxResult.success(result);
    }

    private AjaxResult getIntervalFake(IntervalRequest request) {
        IntervalRequest.IntervalType type = IntervalRequest.IntervalType.getIntervalType(request.getType());
        List<IntervalResponse> result;
        final String deviceSn = request.getDeviceSn();
        switch (type) {
            case DAY:
                //近一天2小时一节点
                result = getFakeDay(deviceSn);
                break;
            case MONTH:
                //近一月1天一节点
                result = getFakeMonth(deviceSn);
                break;
            case SEASON:
                //近三月一星期一节点
                result = getFakeQuarterYear(deviceSn);
                break;
            case HALF_YEAR:
                //近六月一月一节点
                result = getFakeHalfYear(deviceSn);
                break;
            case YEAR:
                //近一年一月一节点
                result = getFakeYear(deviceSn);
                break;
            default:
                throw new CustomException("错误的查询类型");
        }

        //累计一年一节点（最多10年）--不存在此类场景

        return AjaxResult.success(result);
    }

    /**
     * 获取近一年假数据
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getFakeYear(String deviceSn) {
        String key = "MANDUN_INTERVAL_FAKEYEAR:" + deviceSn;
        List<IntervalResponse> cacheList = JsonSerializer.deserializeArray(redisService.getCacheObject(key), IntervalResponse.class);
        if (!CollectionUtils.isEmpty(cacheList)) {
            return cacheList;
        }
        cacheList = new ArrayList<>();
        LocalDate now = LocalDate.now().minusMonths(11L);
        for (int i = 0; i < 12; i++) {
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(now.format(DateTimeFormatter.ofPattern(MM)));
            final BigDecimal min = new BigDecimal("5");
            final BigDecimal max = new BigDecimal("7");
            BigDecimal electricity = RandomUtil.randomBigDecimal(min, max);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(7 * 24), 2, RoundingMode.HALF_UP));
            cacheList.add(each);
            now = now.plusMonths(1L);
        }
        redisService.setCacheObject(key, JsonSerializer.serialize(cacheList), 1, TimeUnit.DAYS);
        return cacheList;
    }

    /**
     * 获取近半年假数据
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getFakeHalfYear(String deviceSn) {
        String key = "MANDUN_INTERVAL_FAKEHALFYEAR:" + deviceSn;
        List<IntervalResponse> cacheList = JsonSerializer.deserializeArray(redisService.getCacheObject(key), IntervalResponse.class);
        if (!CollectionUtils.isEmpty(cacheList)) {
            return cacheList;
        }
        cacheList = new ArrayList<>();
        LocalDate now = LocalDate.now().minusMonths(5L);
        for (int i = 0; i < 6; i++) {
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(now.format(DateTimeFormatter.ofPattern(MM)));
            final BigDecimal min = new BigDecimal("5");
            final BigDecimal max = new BigDecimal("7");
            BigDecimal electricity = RandomUtil.randomBigDecimal(min, max);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(7 * 24), 2, RoundingMode.HALF_UP));
            cacheList.add(each);
            now = now.plusMonths(1L);
        }
        redisService.setCacheObject(key, JsonSerializer.serialize(cacheList), 1, TimeUnit.DAYS);
        return cacheList;
    }

    /**
     * 获取近三个月假数据
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getFakeQuarterYear(String deviceSn) {
        String key = "MANDUN_INTERVAL_FAKEQUARTERYEAR:" + deviceSn;
        List<IntervalResponse> cacheList = JsonSerializer.deserializeArray(redisService.getCacheObject(key), IntervalResponse.class);
        if (!CollectionUtils.isEmpty(cacheList)) {
            return cacheList;
        }
        cacheList = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(String.format("第%s周", i + 1));
            final BigDecimal min = new BigDecimal("5");
            final BigDecimal max = new BigDecimal("7");
            BigDecimal electricity = RandomUtil.randomBigDecimal(min, max);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(7 * 24), 2, RoundingMode.HALF_UP));
            cacheList.add(each);
        }
        redisService.setCacheObject(key, JsonSerializer.serialize(cacheList), 1, TimeUnit.DAYS);
        return cacheList;
    }

    /**
     * 查询近一年，近半年，一个月一节点
     *
     * @param deviceSn
     * @param halfYearFlag
     * @return
     */
    private List<IntervalResponse> getYear(String deviceSn, boolean halfYearFlag) {
        List<IntervalResponse> lastYearInterval = getLastYearInterval(deviceSn, halfYearFlag);
        List<IntervalResponse> thisYearInterval = getThisYearInterval(deviceSn, lastYearInterval, halfYearFlag);
        return thisYearInterval;
    }

    /**
     * 查询近一年，去年的，一月一节点
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getLastYearInterval(String deviceSn, boolean halfYearFlag) {
        LocalDate now = LocalDate.now();
        List<IntervalResponse> result = new ArrayList<>();
        //如果是查询半年
        if (halfYearFlag) {
            now = now.minusMonths(5L);
        } else {
            now = now.minusMonths(11L);
        }
        if (LocalDate.now().getYear() == now.getYear()) {
            return result;
        }
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.MONTH);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, Convert.toStr(now.getYear()));
        params.put(MandunConstant.MONTH, StringUtils.EMPTY);
        params.put(MandunConstant.DAY, StringUtils.EMPTY);
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询年度区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        Map<String, Object> serialize;
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询去年区间用电量返回data为空");
            serialize = new HashMap<>();
        } else {
            //从01到12
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }

        int j = 0;
        int monthValue = now.getMonthValue();
        for (int i = monthValue; i <= 12; i++) {
            String st = leftPadding(i);
            List<MandunIntervalElectricityConsumption> interval;
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                interval = Collections.singletonList(new MandunIntervalElectricityConsumption());
            } else {
                interval = JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class);
            }
            j++;
            IntervalResponse each = new IntervalResponse();
            each.setIndex(j);
            each.setDesc(now.format(DateTimeFormatter.ofPattern(MM)));
            BigDecimal electricity = interval.stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get();
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(30 * 24), 2, RoundingMode.HALF_UP));
            result.add(each);
            now = now.plusMonths(1L);
        }
        return result;
    }

    /**
     * 查询近一年，半年。今年的，一月一节点
     *
     * @param deviceSn
     * @param result
     * @param halfYearFlag
     * @return
     */
    private List<IntervalResponse> getThisYearInterval(String deviceSn, List<IntervalResponse> result, boolean halfYearFlag) {
        Map<String, String> params = new HashMap<>();
        LocalDate now = LocalDate.now();
        int monthValue = now.getMonthValue();
        params.put(MandunConstant.TYPE, MandunConstant.MONTH);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, Convert.toStr(now.getYear()));
        params.put(MandunConstant.MONTH, StringUtils.EMPTY);
        params.put(MandunConstant.DAY, StringUtils.EMPTY);
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询年度区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        Map<String, Object> serialize;
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询今年区间用电量返回data为空");
            serialize = new HashMap<>();
        } else {
            //从01到12
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }

        //如果是查半年的
        if (halfYearFlag) {
            now = now.minusMonths(5L);
        } else {
            now = now.minusMonths(11L);
        }
        int start;
        if (LocalDate.now().getYear() == now.getYear()) {
            start = now.getMonthValue();
        } else {
            start = 1;
            now = LocalDate.parse(String.format("%s-01-%s", LocalDate.now().getYear(), LocalDate.now().getDayOfMonth()));
        }
        int j = result.size() + 1;
        for (int i = start; i <= monthValue; i++) {
            String st = leftPadding(i);
            List<MandunIntervalElectricityConsumption> thisYearInterval;
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                thisYearInterval = Collections.singletonList(new MandunIntervalElectricityConsumption());
            } else {
                thisYearInterval = JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class);
            }
            IntervalResponse each = new IntervalResponse();
            each.setIndex(j);
            j++;
            each.setDesc(now.format(DateTimeFormatter.ofPattern(MM)));
            BigDecimal electricity = thisYearInterval.stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get();
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(30 * 24), 2, RoundingMode.HALF_UP));
            result.add(each);
            now = now.plusMonths(1L);
        }
        return result;
    }

    /**
     * 近三月一星期一节点
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getQuarterYearResult(String deviceSn) {
        LocalDate quarterYearAgo = LocalDate.now().minusMonths(3L);
        List<List<MandunIntervalElectricityConsumption>> interval = new ArrayList<>();
        int year = quarterYearAgo.getYear();
        int monthValue = quarterYearAgo.getMonthValue();
        int startDay = quarterYearAgo.getDayOfMonth();
        int endDay = 31;
        for (int i = 0; i <= 3; i++) {
            if (i == 3) {
                endDay = quarterYearAgo.getDayOfMonth();
            }
            interval = this.getDaysByMonth(deviceSn, Convert.toStr(year), Convert.toStr(monthValue), startDay, endDay, interval);
            quarterYearAgo = quarterYearAgo.plusMonths(1L);
            year = quarterYearAgo.getYear();
            monthValue = quarterYearAgo.getMonthValue();
            startDay = 1;
        }
        List<IntervalResponse> result = new ArrayList<>();
        List<List<List<MandunIntervalElectricityConsumption>>> partition = Lists.partition(interval, 7);
        for (int i = 0; i < partition.size(); i++) {
            List<List<MandunIntervalElectricityConsumption>> lists = partition.get(i);
            if (CollectionUtils.isEmpty(lists)) {
                continue;
            }
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(String.format("第%s周", i + 1));
            BigDecimal electricity = new BigDecimal(0);
            for (int i1 = 0; i1 < lists.size(); i1++) {
                electricity = electricity.add(interval.get(i).stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get());
            }
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(7 * 24), 2, RoundingMode.HALF_UP));
            result.add(each);
        }
        return result;
    }

    /**
     * 按月查询，查每天的
     *
     * @param deviceSn
     * @param year
     * @param month
     * @param list
     * @return
     */
    private List<List<MandunIntervalElectricityConsumption>> getDaysByMonth(String deviceSn, String year, String month, int startDay, int endDay, List<List<MandunIntervalElectricityConsumption>> list) {
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.DAY);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, year);
        params.put(MandunConstant.MONTH, month);
        params.put(MandunConstant.DAY, StringUtils.EMPTY);
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询近一个月区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        if (ObjectUtils.isEmpty(data)) {
            log.info("按天查询月区间用电量返回data为空");
            return list;
        }
        //从01到31(或28或30)
        Map<String, Object> serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        for (int i = startDay; i <= endDay; i++) {
            String st = leftPadding(i + 1);
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                continue;
            }
            list.add(JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class));
        }
        return list;
    }

    private List<IntervalResponse> getFakeMonth(String deviceSn) {
        String key = "MANDUN_INTERVAL_FAKEMONTH:" + deviceSn;
        final List<IntervalResponse> fakeMonth = JsonSerializer.deserializeArray(redisService.getCacheObject(key), IntervalResponse.class);
        if (!CollectionUtils.isEmpty(fakeMonth)) {
            return fakeMonth;
        }
        List<IntervalResponse> result = new ArrayList<>();
        LocalDate lastMonth = LocalDate.now().minusMonths(1L);
        final int lastMonthstart = lastMonth.getDayOfMonth();
        final int lastMonthEnd = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        int left = lastMonthEnd - lastMonthstart;
        final int right = LocalDate.now().getDayOfMonth();
        int size = right + left;
        for (int i = 0; i < size; i++) {
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(lastMonth.format(DateTimeFormatter.ofPattern(DD)));
            BigDecimal min = new BigDecimal("6");
            BigDecimal max = new BigDecimal("10");
            BigDecimal electricity = RandomUtil.randomBigDecimal(min, max).setScale(2, RoundingMode.HALF_UP);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(1 * 24), 2, RoundingMode.HALF_UP));
            result.add(each);
            lastMonth = lastMonth.plusDays(1L);
        }
        redisService.setCacheObject(key, JsonSerializer.serialize(result), 1, TimeUnit.DAYS);
        return result;
    }

    /**
     * 查询月区间电量，近一月1天一节点
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getMonth(String deviceSn) {
        List<List<MandunIntervalElectricityConsumption>> lastYearInterval = getLastMonthInterval(deviceSn);
        List<List<MandunIntervalElectricityConsumption>> thisYearInterval = getThisMonthInterval(deviceSn, lastYearInterval);
        List<IntervalResponse> result = new ArrayList<>();
        LocalDate lastMonth = LocalDate.now().minusMonths(1L).plusDays(1L);
        for (int i = 0; i < thisYearInterval.size(); i++) {
            List<MandunIntervalElectricityConsumption> interval = thisYearInterval.get(i);
            if (CollectionUtils.isEmpty(interval)) {
                continue;
            }
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i);
            each.setDesc(lastMonth.format(DateTimeFormatter.ofPattern(DD)));
            BigDecimal electricity = interval.stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get();
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(1 * 24), 2, RoundingMode.HALF_UP));
            result.add(each);
            lastMonth = lastMonth.plusDays(1L);
        }
        return result;
    }

    /**
     * 查询上月区间电量，近一月5天一节点
     *
     * @param deviceSn
     * @return
     */
    private List<List<MandunIntervalElectricityConsumption>> getLastMonthInterval(String deviceSn) {
        int nowMonth = LocalDate.now().getMonthValue();
        LocalDate lastMonth = LocalDate.now().minusMonths(1L).plusDays(1L);
        int lastMonthValue = lastMonth.getMonthValue();
        List<List<MandunIntervalElectricityConsumption>> list = new ArrayList<>();
        if (nowMonth == lastMonthValue) {
            return list;
        }
        int start = lastMonth.getDayOfMonth();
        int end = lastMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.DAY);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, Convert.toStr(lastMonth.getYear()));
        params.put(MandunConstant.MONTH, Convert.toStr(lastMonthValue));
        params.put(MandunConstant.DAY, StringUtils.EMPTY);
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询近一个月区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        //从01到31(或28或30)
        Map<String, Object> serialize;
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询上月区间用电量返回data为空");
            serialize = new HashMap<>();
        } else {
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }

        for (int i = start; i <= end; i++) {
            String st = leftPadding(i);
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                //占位
                list.add(Collections.singletonList(new MandunIntervalElectricityConsumption()));
                continue;
            }
            list.add(JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class));
        }
        return list;
    }

    /**
     * 查询当月区间电量，近一月5天一节点
     *
     * @param deviceSn
     * @param lastMonth
     * @return
     */
    private List<List<MandunIntervalElectricityConsumption>> getThisMonthInterval(String deviceSn, List<List<MandunIntervalElectricityConsumption>> lastMonth) {
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.DAY);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, Convert.toStr(LocalDate.now().getYear()));
        params.put(MandunConstant.MONTH, Convert.toStr(LocalDate.now().getMonthValue()));
        params.put(MandunConstant.DAY, StringUtils.EMPTY);
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询近一个月区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        Map<String, Object> serialize;
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询当月区间用电量返回data为空");
            serialize = new HashMap<>();
        } else {
            //从01到31(或28或30)
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }
        int end = LocalDate.now().getDayOfMonth();
        for (int i = 1; i <= end; i++) {
            String st = leftPadding(i);
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                //占位
                lastMonth.add(Collections.singletonList(new MandunIntervalElectricityConsumption()));
                continue;
            }
            lastMonth.add(JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class));
        }
        return lastMonth;
    }

    /**
     * 获取当天的假数据
     *
     * @return
     */
    private List<IntervalResponse> getFakeDay(String deviceSn) {
        final String key = "MANDUN_INTERVAL_FAKEDAY:" + deviceSn;
        final List<IntervalResponse> mandun_fakeDay = JsonSerializer.deserializeArray(redisService.getCacheObject(key), IntervalResponse.class);
        if (!CollectionUtils.isEmpty(mandun_fakeDay)) {
            return mandun_fakeDay;
        }
        List<IntervalResponse> result = new ArrayList<>();
        LocalTime yesterday = LocalTime.now().minusHours(24);
        for (int i = 0; i < 24; i++) {
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i / 2);
            yesterday = yesterday.plusHours(2L);
            each.setDesc(yesterday.format(DateTimeFormatter.ofPattern(HH)));
            i = i + 1;
            BigDecimal min = new BigDecimal("0.25");
            BigDecimal max = new BigDecimal("0.4");
            BigDecimal electricity = RandomUtil.randomBigDecimal(min, max).setScale(2, RoundingMode.HALF_UP);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(2), 2, RoundingMode.HALF_UP));
            result.add(each);
        }
        redisService.setCacheObject(key, JsonSerializer.serialize(result), 1, TimeUnit.HOURS);
        return result;
    }

    /**
     * 获取近一天用电量，2小时一节点
     *
     * @param deviceSn
     * @return
     */
    private List<IntervalResponse> getDay(String deviceSn) {
        List<List<MandunIntervalElectricityConsumption>> yesterdayInterval = this.getYesterdayInterval(deviceSn);
        List<List<MandunIntervalElectricityConsumption>> todayInterval = this.getTodayInterval(deviceSn, yesterdayInterval);
        List<IntervalResponse> result = new ArrayList<>();
        LocalTime yesterday = LocalTime.now().minusHours(24);
        for (int i = 0; i < todayInterval.size(); i++) {
            if (i == todayInterval.size() || (i + 1) == todayInterval.size()) {
                continue;
            }
            IntervalResponse each = new IntervalResponse();
            each.setIndex(i / 2);
            yesterday = yesterday.plusHours(2L);
            each.setDesc(yesterday.format(DateTimeFormatter.ofPattern(HH)));
            BigDecimal partOne = todayInterval.get(i).stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get();
            i = i + 1;
            BigDecimal partTwo = todayInterval.get(i).stream().map(MandunIntervalElectricityConsumption::getElectricity).reduce(BigDecimal::add).get();
            BigDecimal electricity = partOne.add(partTwo);
            each.setElectricity(electricity.setScale(2, RoundingMode.HALF_UP));
            each.setCurrentPower(electricity.divide(new BigDecimal(2), 2, RoundingMode.HALF_UP));
            result.add(each);
        }
        return result;
    }

    /**
     * 查询当日 小时区间电量
     *
     * @param deviceSn
     * @return
     */
    private List<List<MandunIntervalElectricityConsumption>> getTodayInterval(String deviceSn, List<List<MandunIntervalElectricityConsumption>> yesterdayInterval) {
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.HOUR);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        params.put(MandunConstant.YEAR, Convert.toStr(LocalDate.now().getYear()));
        params.put(MandunConstant.MONTH, Convert.toStr(LocalDate.now().getMonthValue()));
        params.put(MandunConstant.DAY, Convert.toStr(LocalDate.now().getDayOfMonth()));
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询昨日小时区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        Map<String, Object> serialize = new HashMap<>();
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询今日区间电量返回data为空");
            serialize = new HashMap<>();
        } else {
            //从00到23
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }
        int hour = LocalDateTime.now().getHour();
        for (int i = 0; i < hour; i++) {
            String st = leftPadding(i);
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                //占位
                yesterdayInterval.add(Collections.singletonList(new MandunIntervalElectricityConsumption()));
                continue;
            }
            yesterdayInterval.add(JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class));
        }
        return yesterdayInterval;
    }

    /**
     * 查询昨日 小时区间电量
     *
     * @param deviceSn
     * @return
     */
    private List<List<MandunIntervalElectricityConsumption>> getYesterdayInterval(String deviceSn) {
        Map<String, String> params = new HashMap<>();
        params.put(MandunConstant.TYPE, MandunConstant.HOUR);
        params.put(MandunConstant.DEVICE_SN, deviceSn);
        LocalDate yesterday = LocalDate.now().minusDays(1L);
        params.put(MandunConstant.YEAR, Convert.toStr(yesterday.getYear()));
        params.put(MandunConstant.MONTH, Convert.toStr(yesterday.getMonthValue()));
        params.put(MandunConstant.DAY, Convert.toStr(yesterday.getDayOfMonth()));
        AjaxResult consumption = this.getIntervalElectricityConsumption(params);
        if (!consumption.isSuccess()) {
            log.error("查询昨日小时区间用电量异常");
            throw new CustomException(consumption.getMsg());
        }
        Object data = consumption.getData();
        List<List<MandunIntervalElectricityConsumption>> list = new ArrayList<>();
        Map<String, Object> serialize;
        if (ObjectUtils.isEmpty(data)) {
            log.info("查询昨日区间电量返回data为空");
            serialize = new HashMap<>();
        } else {
            //从00到23
            serialize = JsonSerializer.deserializeMap(JsonSerializer.serialize(data));
        }

        int start = LocalTime.now().getHour();
        for (int i = start; i < 24; i++) {
            String st = leftPadding(i);
            if (ObjectUtil.isEmpty(serialize.get(st))) {
                //占位
                list.add(Collections.singletonList(new MandunIntervalElectricityConsumption()));
                continue;
            }
            list.add(JsonSerializer.deserializeArray(JsonSerializer.serialize(serialize.get(st)), MandunIntervalElectricityConsumption.class));
        }
        return list;
    }

    //调用曼顿
    public AjaxResult getIntervalElectricityConsumption(Map<String, String> params) {
        int minute = 60 * 24;
        String type = params.get(MandunConstant.TYPE);//查询类型
        //获取查询接口
        String method = MandunIntervalEnum.getRouter(type);
        String mac = params.get(MandunConstant.DEVICE_SN);
        String year = params.get(MandunConstant.YEAR);
        String month = params.get(MandunConstant.MONTH);
        String day = Convert.toStr(params.get(MandunConstant.DAY), StringUtils.EMPTY);
        String hour = Convert.toStr(params.get(MandunConstant.HOUR), StringUtils.EMPTY);
//        String sql =
//                String.format("select * from mandun_interval_electricity_consumption where mac = '%s' and year = '%s' ", mac, year);
//        if (StringUtils.isNotEmpty(month)) {
//            sql = String.format("%s and month = '%s'", sql, month);
//        }
//        if (StringUtils.isNotEmpty(day)) {
//            sql = String.format("%s and day = '%s'", sql, day);
//        }
//        if (StringUtils.isNotEmpty(hour)) {
//            sql = String.format("%s and hour = '%s'", sql, hour);
//        }
//        sql = String.format("%s and  time > now() - %sm ", sql, minute);
        //查询时序数据库存在则返回
//        Query query = new Query(sql, "paramter_db");
//        List<MandunIntervalElectricityConsumption> products = influxCustomMapper.query(query, MandunIntervalElectricityConsumption.class);
//        if (CollectionUtils.isNotEmpty(products)) {
//            return AjaxResult.success(products);
//        }

        TreeMap request = MandunUtil.getCommonRequest(method, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);//电箱编号(mac最多20个，以逗号分隔)，给前端只允许查一个，否则难解析
        request.put(MandunConstant.YEAR, year);//必传
        request.put(MandunConstant.MONTH, month);//三方接口查询月份时可不传，但给前端都必传，否则格式很难解析。
        if (type.equals(MandunConstant.DAY) || type.equals(MandunConstant.HOUR)) {
            request.put(MandunConstant.DAY, day);//查询天时可不传
        }
        if (type.equals(MandunConstant.HOUR)) {
            request.put(MandunConstant.HOUR, hour);//查询小时 可不传
        }
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(jsonObject.getString(MandunConstant.MESSAGE));
        }
        //可能是map或list
        Object data = jsonObject.getJSONObject(MandunConstant.DATA).get(mac);
//        List<MandunIntervalElectricityConsumption> consumptionList = JsonSerializer.deserializeArray(JsonSerializer.serialize(data), MandunIntervalElectricityConsumption.class);
//        consumptionList.stream().forEach(item -> {
//            item.setType(type);
//            item.setYear(year);
//            item.setMonth(month);
//            item.setDay(day);
//            item.setHour(hour);
//            item.setDeviceSn(mac);
//        });
//        for (MandunIntervalElectricityConsumption item : consumptionList) {
//            influxCustomMapper.save(item);
//        }
        return AjaxResult.success(data);
    }

    @Override
    public MandunOnlineHistory getBoxOnlineHistory(String mac, String startTime, String endTime) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX_ONLINE_HISTORY, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, config.getProjectCode());
        request.put(MandunConstant.START_TIME, startTime);
        request.put(MandunConstant.END_TIME, endTime);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        return JsonSerializer.deserialize(JsonSerializer.serialize(jsonObject), MandunOnlineHistory.class);
    }

    @Override
    public AjaxResult subscribePushService(byte pushType) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_SUBSCRIBE_PUSH_SERVICE, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.PUSH_TYPE, pushType);//推送类型 1 告警；2 实时数据；3事件通知
        request.put(MandunConstant.CMD, "SUBSCRIBE");//订阅告警
        request.put(MandunConstant.URL, getPushUrl(pushType));//推送接口地址（系统会对接口进行验证，请参考文档中“通知接口”的要求进行实现）
        request.put(MandunConstant.SALT, "salt");//加密盐值 如：abc
        request.put(MandunConstant.TIME_RANGES, "00:00~23:59");//推送时间段，支持多个时间段（逗号分隔，如: 08:00~12:00,13:30~22:00）
        request.put(MandunConstant.PUSH_ENABLE, "1");//推送状态（0:不推送； 1:推送）
        request.put(MandunConstant.TYPE_NUMBERS, 1 == pushType ? "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19" : MandunConstant.ZERO);
//        request.put(MandunConstant.PUSH_MODE, "1");//推送模式（非必填！当值为"1"时：批量推送，否则：逐条推送，）不用传
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));

        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success(MandunUtil.getMsg(jsonObject));
    }

    private String getPushUrl(byte pushType) {
        //1 告警；2 实时数据；3事件通知
        String url = config.getCallBackPrefix();
        switch (pushType) {
            case 1:
                url += "mandun/receiveAlarm";
                break;
            case 2:
                url += "mandun/receiveRealTime";
                break;
            case 3:
                url += "mandun/receiveEvent";
                break;
            default:
                url = StringUtils.EMPTY;
        }
        return url;
    }

    private long convertOnline(boolean online) {
        if (online) {
            return 1L;
        }
        return 0L;
    }

    /**
     * 2位数字左侧补0，用于时间，日期等
     *
     * @param num
     * @return
     */
    private String leftPadding(int num) {
        return String.format("%02d", num);
    }

    /**
     * 删除推送
     *
     * @param pushType
     * @return
     */
    @Override
    public AjaxResult unsubscribe(byte pushType) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_SUBSCRIBE_PUSH_SERVICE, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.PUSH_TYPE, pushType);
        request.put(MandunConstant.CMD, "UNSUBSCRIBE");//删除订阅告警
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));

        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success(MandunUtil.getMsg(jsonObject));
    }

    /**
     * 查询已订阅的推送
     *
     * @param pushType
     * @return
     */
    @Override
    public AjaxResult querySubscribe(byte pushType) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_SUBSCRIBE_PUSH_SERVICE, config.getAppKey(), getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.PUSH_TYPE, pushType);
        request.put(MandunConstant.CMD, "UNSUBSCRIBE");//删除订阅告警
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));

        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.doPoststr(config.getUrlPrefix() + config.getRouterSuffix(), JsonSerializer.serialize(request), headers);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success(jsonObject.getJSONObject(MandunConstant.DATA));
    }

    @Override
    public String refreshToken(MandunConfig config, String refreshToken) {
        log.info("开始刷新token，尝试获取redis锁");
        final String redisValue = RandomUtil.randomString(30);
        try {
            final boolean tryLock = distributeLock.tryLock(redisValue, 5000L);
            if (tryLock) {
                log.info("开始刷新token，获取到redis锁");
                JSONObject jsonObject = MandunUtil.refreshToken(config, refreshToken);
                if (MandunUtil.isExpire(jsonObject)) {
                    log.info("刷新token失败，refreshToken失效，重新授权token");
                    redisService.deleteObject(MandunConstant.MANDUN_ACCESS_TOKEN);
                    redisService.deleteObject(MandunConstant.MANDUN_REFRESH_TOKEN_KEY);
                    return this.accessToken(config, redisValue);
                }
                JSONObject data = jsonObject.getJSONObject(MandunConstant.DATA);
                String accessToken = data.getString(MandunConstant.ACCESS_TOKEN);
                this.setToken2Redis(data.getString(MandunConstant.REFRESH_TOKEN), accessToken);
                return accessToken;
            } else {
                log.info("开始刷新token，未取到redis锁，等待获取accessToken");
                try {
                    Thread.sleep(2999);
                    return redisService.getCacheObject(MandunConstant.MANDUN_ACCESS_TOKEN);
                } catch (InterruptedException e) {
                    log.error("等待获取accessToken，发生异常");
                }
            }
            log.error("刷新token异常");
            return StringUtils.EMPTY;
        } finally {
            distributeLock.releaseLock(redisValue);
        }
    }

    /**
     * 获取token,跟刷新token使用同一个redis锁的key
     *
     * @param config
     * @param lockValue
     * @return
     */
    @Override
    public String accessToken(MandunConfig config, String lockValue) {
        log.info("开始获取token，尝试获取redis锁");
        String redisValue;
        if (StringUtils.isEmpty(lockValue)) {
            redisValue = RandomUtil.randomString(30);
        } else {
            redisValue = lockValue;
        }
        try {
            boolean tryLock = distributeLock.tryLock(redisValue, 5000L);
            if (tryLock) {
                log.info("开始获取token，获取到redis锁");
                JSONObject tokenObj = MandunUtil.getToken(config);
                JSONObject data = tokenObj.getJSONObject(MandunConstant.DATA);
                String accessToken = data.getString(MandunConstant.ACCESS_TOKEN);
                String refreshToken = data.getString(MandunConstant.REFRESH_TOKEN);
                this.setToken2Redis(refreshToken, accessToken);
                return accessToken;
            } else {
                log.info("开始获取token，未取到redis锁，线程休眠，等待获取其他线程刷新的token");
                try {
                    Thread.sleep(2999);
                    return redisService.getCacheObject(MandunConstant.MANDUN_ACCESS_TOKEN);
                } catch (InterruptedException e) {
                    log.error("等待获取accessToken，发生异常");
                }
            }
            log.error("等待获取accessToken异常");
            return StringUtils.EMPTY;
        } finally {
            distributeLock.releaseLock(redisValue);
        }
    }
}
